package com.allwees.bs.c.module.order.context.processor;

import com.allwees.bs.c.module.order.entity.OrderEntity;
import com.allwees.bs.c.module.order.entity.OrderItemEntity;
import com.allwees.bs.c.module.order.mq.event.OrderItemApplyRefundEvent;
import com.allwees.bs.c.module.order.mq.event.OrderReceivedMqEvent;
import com.allwees.bs.c.module.order.repository.OrderItemRepository;
import com.allwees.bs.c.module.order.repository.OrderRefundRepository;
import com.allwees.bs.c.module.order.repository.OrderRepository;
import com.allwees.bs.c.module.payment.entity.PaymentLogEntity;
import com.allwees.bs.c.module.payment.repository.PaymentLogRepository;
import com.allwees.bs.c.module.product.repository.ProductRepository;
import com.allwees.bs.c.module.product.service.ProductService;
import com.allwees.bs.core.model.order.config.ScheduleTimeProperties;
import com.allwees.bs.core.model.order.wf.order.EOrderAction;
import com.allwees.bs.core.model.order.wf.order.EOrderItemAction;
import com.allwees.bs.core.model.order.wf.order.EOrderItemState;
import com.allwees.bs.core.model.order.wf.refund.ERefundState;
import com.allwees.bs.core.modelbase.constant.ResultEnum;
import com.allwees.bs.core.modelbase.exception.BusinessException;
import com.allwees.core.common.util.DateUtil;
import com.allwees.core.mq.rabbitmq.MqUtil;
import com.allwees.support.payment.EPayMethod;
import com.allwees.support.payment.model.RefundInfo;
import com.allwees.support.payment.oceanpay.CreditCardStrategy;
import com.allwees.support.payment.paypal.PaypalAccountStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

@Slf4j
@Component
public class OrderPostProcessor {
    @Autowired
    private ProductRepository productRepository;

    @Resource
    private ProductService productService;

    @Autowired
    private ScheduleTimeProperties scheduleTimeProperties;

    @Autowired
    private OrderItemRepository orderItemRepository;

    @Autowired
    private OrderRefundRepository orderRefundRepository;

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private PaymentLogRepository paymentLogRepository;


//    @Autowired
//    private CashActiveDefUseService cashActiveDefUseService;

    /**
     * 用户支付订单处理
     *
     * @param orderItems
     */
    public void userPayedProcess(List<OrderItemEntity> orderItems, Date paymentAt, boolean cod) {
        //库存扣减
        orderItems.forEach(item -> {
            productService.decInventory(item.getSkuUuid(), item.getQuantity());
        });

        Date canShippingAt = DateUtil.addSeconds(paymentAt, scheduleTimeProperties.getOrderPayAfterFreezeSecond());
        orderItems.forEach(item -> {
            item.setCanShippingAt(canShippingAt);
            item.setRefundExpiredAt(DateUtil.addSeconds(new Date(), scheduleTimeProperties.getOrderRefundNotNeedAuditSecond()));
            if (cod) {
                item.signal(EOrderItemAction.USER_COD);
                item.setPaymentAt(null);
            } else {
                item.signal(EOrderItemAction.USER_PAYED);
                item.setPaymentAt(paymentAt);
            }
            orderItemRepository.save(item);
        });
    }

    /**
     * 用户取消订单处理
     *
     * @param orderUuid
     */
    public void userCancelProcess(String orderUuid) {
        List<OrderItemEntity> orderItems = orderItemRepository.findOrderItems(orderUuid);

        for (OrderItemEntity orderItem : orderItems) {

            orderItem.signal(EOrderItemAction.USER_CANCEL);
            orderItemRepository.save(orderItem);

//            this.skuRepository.updateAppendQuantity(orderItem.getSkuUuid(), orderItem.getQuantity() * -1);
            productService.addInventory(orderItem.getSkuUuid(), orderItem.getQuantity());
        }
    }

    /**
     * 用户收货处理
     *
     * @param orderItemUuid
     */
    public void userReceivedProcess(String orderItemUuid) {
        Date now = new Date();
        OrderItemEntity orderItem = orderItemRepository.getByUuid(orderItemUuid);
          if (!EOrderItemState.DELIVERED.equals(orderItem.getState())) {
            throw BusinessException.getInstance(ResultEnum.ORDER_CANNOT_DELIVER);
        }
       /* orderItems.forEach(orderItem -> {
            if (!orderItem.ended()) {
                _userReceivedProcess(now, orderItem);
            }
        });*/
        _userReceivedProcess(now, orderItem);



        //只有已妥投状态才能确认收货
       /* if (!EOrderState.SHIPPED.equals(order.getState())) {
            throw BusinessException.getInstance(ResultEnum.ORDER_CANNOT_CONFIRM_SHIPPING);
        }*/

        // order.signal(EOrderAction.USER_CONFIRM_RECEIVED);
        //order.setReceiveAt(new Date());
        //orderRepository.save(order);
        MqUtil.send(new OrderReceivedMqEvent(orderItemUuid));
    }

    /**
     * 用户评论订单处理
     *
     * @param orderItem
     */
    public void userReviewedProcess(OrderEntity order, OrderItemEntity orderItem) {
        //条件变迁
        orderItem.signal(EOrderItemAction.USER_REVIEWED);
        orderItem.setReviewAt(DateUtil.now());
        orderItemRepository.save(orderItem);

        // 增加评论数
        this.productRepository.updateAppendTotalReviews(orderItem.getProductUuid());

//        ProductActionLogUtil.logProduct(EActionType.P_REVIEW, orderItem.getProductUuid());

        int refundCount = orderRefundRepository.getCountByOrderUuidAndState(order.getUuid(), ERefundState.COMPLETED);
        Integer unreviewItemCount = orderItemRepository.getUnreviewItemCount(order.getUuid());
        if (unreviewItemCount > 0 && unreviewItemCount != refundCount) {
            return;
        }
        order.signal(EOrderAction.USER_ALL_REVIEWED);
        orderRepository.save(order);
    }

    /**
     * 用户退款处理
     */
    public void userRefundProcess(boolean condition, String orderUuid, String orderItemUuid) {
        if (!condition) {
            return;
        }
        _refundAmt(orderItemUuid);

        MqUtil.send(new OrderItemApplyRefundEvent(orderItemUuid));
//        _userRefundProcess(orderUuid);
    }



    /**
     * 用户退款处理
     */
    private void _userRefundProcess(String orderUuid) {

        OrderEntity order = orderRepository.getByUuid(orderUuid);

        int orderRefundCount = orderRefundRepository.getCountByOrderUuidAndState(orderUuid, ERefundState.COMPLETED);
        if (orderRefundCount == 0 || orderRefundCount < order.getQuantity()) {
            return;
        }

        order.signal(EOrderAction.SYSTEM_CLOSE_BY_ALL_REFUND);
        orderRepository.save(order);
    }

    private void _userReceivedProcess(Date now, OrderItemEntity orderItem) {

        Date reviewExpiredAt = DateUtil.addSeconds(now, scheduleTimeProperties.getOrderReviewOnReceivedSecond());
        Date refundExpiredAt = DateUtil.addSeconds(now, scheduleTimeProperties.getOrderRefundOnReceivedSecond());

        orderItem.setReviewExpiredAt(reviewExpiredAt);
        orderItem.setRefundExpiredAt(refundExpiredAt);

        orderItem.signal(EOrderItemAction.USER_CONFIRM_RECEIVED);
        this.orderItemRepository.save(orderItem);
    }

    public void _refundAmt(String orderItemUuid) {

        OrderItemEntity orderItem = orderItemRepository.getByUuid(orderItemUuid);
        //todo add by zhouyw Mock和订单金额为0时直接返回
        if (orderItem.getPlatform().isMock() || BigDecimal.ZERO.compareTo(orderItem.getAmt()) == 0) {
            return;
        }

        PaymentLogEntity paymentLog = paymentLogRepository.findByOrderUuid(orderItem.getOrderUuid());

        RefundInfo refundInfo = new RefundInfo()
                .setOrderItemUuid(orderItemUuid)
                .setPaymentNo(paymentLog.getPaymentNumber())
                .setAmt(orderItem.getAmt())
                .setCurrency(paymentLog.getCurrency());

        String type = paymentLog.getType();
        if (EPayMethod.PAYPAL.name().equals(type)) {
            PaypalAccountStrategy.refund(refundInfo);
        } else if(EPayMethod.CREDIT_CARD.name().equals(type)) {
            CreditCardStrategy.refund(refundInfo);
        }
    }
}
